﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace BookStore
{
    //Using the Singleton design pattern
    class StoreEngine
    {
        private static StoreEngine _instance;
        private List<Item> allItems;
        private List<Storage> allStorages;
        private List<int> outOfStorage;

        //Ensures that we have only one instance of the StoreEngine class
        public static StoreEngine GetEngine()
        {
            if (_instance == null)
            {
                _instance = new StoreEngine();
            }

            return _instance;
        }

        //Keeps a list of all the items that are out of storage
        void OutOfStorageManagement(object sender, OutOfStorageEventArgs args)
        {
            int allStorageStock = 0;
            for (int i = 0; i < allStorages.Count; i++)
            {
                if (allStorages[i] != sender)
                {
                    allStorageStock += allStorages[i].GetStock(args.ItemId);
                }
            }

            if (allStorageStock == 0)
            {
                outOfStorage.Add(args.ItemId);
                throw new InsufficientStockException<int>(args.ItemId, args.RemainingQuantity);
            }                
        }

        //Returns all objects from type T in the allItems list
        T [] GetAllItemsFromType<T>() where T : Item
        {
            return this.allItems.Where(x => x is T).Cast<T>().ToArray();
        }

        public T [] GetAllAvailableItemsFromType <T>() where T : Item
        {
            return GetAllItemsFromType<T>().Where(x => outOfStorage.IndexOf(x.Id) < 0).ToArray();
        }

        public int ExtractStock(int itemId, int itemQuantity)
        {
            int storeIndex = 0;
            int remainingQuantity = itemQuantity;

            while (storeIndex < allStorages.Count && remainingQuantity > 0)
            {
                remainingQuantity = allStorages[storeIndex].ExtractStock(itemId, remainingQuantity);
                storeIndex++;
            }

            return remainingQuantity;
        }

        //Initializes the engine
        void Initialize()
        {
            outOfStorage = new List<int>();
            allStorages = new List<Storage>() { 
                new Storage ("Office 1 Superstore", "bulevard 'Tsarigradsko shosse' 139, 1784 Sofia"),
                new Storage ("Panda Cooperation", "Sofia, ul. 'Ilia Beshkov' 12 Complex 'Drujba 1', 1528")
            };

            //Link to OutOfStorageEvents
            foreach (Storage storage in allStorages)
            {
                storage.OutOfStorageEvent += OutOfStorageManagement;
            }
            
            allItems = new List<Item>();

            allItems.Add(new E_Book("Jaunt", "KF8", Publisher.AustinMacauley, "Ebook", 7));
            allItems.Add(new E_Book("Jan Bibijan", "EPUB", Publisher.Fiut, "Ebook", 5));

            allItems.Add(new Audio("Rock Guitar", Publisher.Fantero, "Audio", 18, "HD", "DVD"));

            allItems.Add(new Video("Learning Java In 30 Days", Publisher.Technika, "Video", 20, "HD", "DVD", "CBR"));
            allItems.Add(new Video("Like an Ocean Shelf", Publisher.AustinMacauley, "Video", 36, "HD", "DVD", "VBR"));

            allItems.Add(new NonfictionBook("The Forsyte Saga", Publisher.Colibri, "Nonfiction", 16, "John Galsworthy", 1286,  NonfictionGenre.Historical));
            allItems.Add(new NonfictionBook("1,000 pages Bulgaria", Publisher.Ciela, "Nonfiction", 28, "Rumjana Nikolova, Nikolay Genov", 1008,  NonfictionGenre.Enciclopedia));

            allItems.Add(new FictionBook("Salem's Lot", Publisher.HermesBooks, "Fiction", 14, "Stephen King", 1286, FictionGenre.Horror));
            allItems.Add(new FictionBook("The Hound", Publisher.Ciela, "Fiction", 15, "Vladimir Zarev", 320, FictionGenre.Crime)); 

            allItems.Add(new TextBook("Introduction to Programming with C#", Publisher.Enthusiast, "TextBook", 45, "Svetlin Nakov", 1135, Subject.Informatics));
            allItems.Add(new TextBook("Byzantium", Publisher.HermesBooks, "TextBook", 15, "Nikolay Tabakov", 456, Subject.History));

            Audio testAudio = new Audio("Enjoy Daily Life", Publisher.Fantero, "Audio", 29, "SD", "CD");
            testAudio.InitID();
            allItems.Add(testAudio);

            allItems.Add(new Audio("The Epic Journey Of Steam Trains", Publisher.Fantero, "Audio", 28, "HD", "DVD"));
            allItems.Add(new Audio("Finding Our way", Publisher.Fantero, "Audio", 35, "HD", "DVD"));


            allItems.Add(new Video("Eyes Wide Shut", Publisher.RaiderPublishing, "Video", 45, "HD", "DVD", "CBR"));
            allItems.Add(new Video("Bonnie And Clyde", Publisher.IMDb, "Video", 36, "HD", "DVD", "VBR"));

            allItems.Add(new E_Book("The A.B.C. Murders", "KF8", Publisher.NLO_Books, "Ebook", 12));
            allItems.Add(new E_Book("Under The Yoke", "EPUB", Publisher.HermesBooks, "Ebook", 20));
            allItems.Add(new E_Book("Clochemerle-en-Beaujolais", "AZV", Publisher.PenSoft, "Ebook", 37));
            allItems.Add(new E_Book("Max und Moritz", "EPUB", Publisher.Fiut, "Ebook", 10));

            //We add the diferent items in random storage with random amount
            Random rnd = new Random();
            foreach (Item item in allItems)
            {
                allStorages[rnd.Next(0, 2)].AddStock(item.Id, rnd.Next(1, 20));
            }
        }
        
        //Runs the engine
        void Run()
        {
            System.Diagnostics.Debug.WriteLine("Welcome to the Azurite Book and Multimedia Store!\n\nTo navigate through our ordering system, please \nenter the number of the item you wish to go to.\n");
            System.Diagnostics.Debug.WriteLine(new String('*', 58));

            Menu.MenuStart();
        }

        static void Main(string[] args)
        {
            StoreEngine engine = GetEngine();
            engine.Initialize();
            engine.Run();
        }
    }
}
